package com.wetool.service;

import com.wetool.Constant;
import com.wetool.common.model.ItemDto;
import com.wetool.entity.Area;
import com.wetool.entity.BalanceRecord;
import com.wetool.entity.Merchant;
import com.wetool.entity.Shop;
import com.wetool.exception.AccountExistedException;
import com.wetool.exception.AcountNotFoundException;
import com.wetool.exception.MacNotFoundException;
import com.wetool.exception.MerchantNotFoundException;
import com.wetool.feign.ChargeQrCodeClient;
import com.wetool.feign.SmsFeignClient;
import com.wetool.feign.UserFeignClient;
import com.wetool.jpa.BalanceRepo;
import com.wetool.jpa.MerchantItemSpec;
import com.wetool.jpa.MerchantRepo;
import com.wetool.jpa.MerchantSpec;
import com.wetool.jpa.ShopRepo;
import com.wetool.model.*;
import com.wetool.model.Message.Result;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商家业务处理类
 *
 * @author zhangjie
 */
@Component
public class MerchantService {
    private static final Logger logger = LogManager.getLogger(MerchantService.class);

    // 余额新增
    private static final Byte balance_add = 1;
    // 余额减
    private static final Byte balance_sub = 2;
    // 充值返利
    private static final Byte add_profit = 3;
    // 充值失败退款
    private static final Byte balance_refund = 4;

    private static final int merchant_status_ok = 1;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private MerchantRepo merchantRepo;

    @Autowired
    private ShopService shopService;

    @Autowired
    private MacService macService;

    @Autowired
    private LoginService loginService;

    @Autowired
    private CaptchaService captchaService;

    @Autowired
    private BalanceRepo balanceRepo;

    @Autowired
    private SmsFeignClient smsFeignClient;

    @Autowired
    private ChargeQrCodeClient chargeQrCodeClient;

    @Autowired
    private AreaService areaService;

    /**
     * 商家查询
     *
     * @param param
     * @param p     分页参数
     * @return 商家对象集合
     */
    public Page<Merchant> find(SearchParam param, Pageable p) {
        MerchantSpec spec = new MerchantSpec(param);
        Page<Merchant> merchants = merchantRepo.findAll(spec, p);
        return merchants;
    }

    /**
     * 商家查询
     *
     * @param id 商家KEY（主键）
     * @return 商家对象
     */
    public Merchant findOne(Long id) {
        return merchantRepo.getByIdAndIsDeleted(id, false);
    }

    /**
     * 商家查询
     *
     * @param mobile 商家手机号
     * @return 商家对象
     */
    public Merchant findByMobile(String mobile) {
        return merchantRepo.findByMobile(mobile);
    }
    

    /**
     * 商家查询
     *
     * @param username 商家管理主帐号
     * @return 商家对象
     */
    public Merchant findByUsername(String username) {
        return merchantRepo.findByUsername(username);
    }

    /**
     * 新增商家
     *
     * @param param 请求参数 店铺经营类型
     * @return
     * @throws Exception
     * @throws AccountExistedException
     */
    @Transactional
    public Map<String, Object> add(MerchantRegister param) throws AccountExistedException, Exception {
        String mobile = param.getMobile();
        String roleKey = Constant.ROLE_KEY_SHOP; // 单体店商家角色
        Integer userType = Constant.USER_SHOP; // 用户类型（单体店商家）

		/* 校验验证码 */
        String key = Constant.CATCHA_REGISTER + mobile; // 商家注册验证码Key=R_手机号
        captchaService.verify(key, param.getCaptcha());

		/* 校验设备信息是否正常 */
        if (!macService.verifyMacSn(param.getMacSn())) {
            throw new MacNotFoundException();
        }

		/* 密码格式化类（必须为6位密码） */
        DecimalFormat pwdFormat = new DecimalFormat("000000");

		/* 创建商家帐号 */
        int imPwd = new Random().nextInt(999999); // 随机6位密码
        String merchantPwd = pwdFormat.format(imPwd);
        Acount acount = new Acount(mobile, merchantPwd, mobile, userType, roleKey);
        ResponseEntity<Message<?>> response = userFeignClient.register(acount);
        Message<?> message = response.getBody();
        switch (message.getCode()) {
            case 0: // 成功状态
                Map<String, Object> data = (Map<String, Object>) message.getData();
                logger.debug("商家帐号创建完成, userId【{}】", data.get("userId"));
                break;
            case 3: // 帐号已存在
                throw new AccountExistedException();
            default: // 其它状态码全部判定为异常
                throw new Exception();
        }

		/* 新增商家 */
        Merchant merchant = new Merchant();
        BeanUtils.copyProperties(param, merchant); // 属性复制
        merchant.setUsername(mobile); // 以手机号作为登录帐号
        merchant.setPayPwd(Constant.DEFAULT_PWD); // 设置默认支付密码

		/* 省/市/区 处理 */
        if (param.getDistrict() != null && param.getCity() != null && param.getProvince() != null) {
            Area area = areaService.getArea(param.getProvince(), param.getCity(), param.getDistrict());
            merchant.setArea(area);
        }
        merchant = merchantRepo.saveAndFlush(merchant);
        Long merchantId = merchant.getId();

		/* 自动新增店铺 */
        ShopRegister shopRegister = new ShopRegister();
        BeanUtils.copyProperties(param, shopRegister); // 属性复制

		/* 创建商家帐号 */
        int iPwd = new Random().nextInt(999999); // 随机6位密码
        String password = pwdFormat.format(iPwd);
        shopRegister.setPassword(password);

        Shop shop = shopService.addAndBindMac(shopRegister, merchant);
        Token token = loginService.login(shop.getUsername(), password);

		/* 构造短信内容 */
        // StringBuffer sms = new StringBuffer();
        // sms.append(mobile).append("/").append(merchantPwd);
        // smsFeignClient.sendSms(mobile, Constant.SMS_TYPE_OK_REGISTER,
        // URLEncoder.encode(sms.toString())); // 下发注册成功短信通知
        return new HashMap<String, Object>() {
            private static final long serialVersionUID = 1L;

            {
                put("token", token);
            }

            {
                put("merchantId", merchantId);
            }

            {
                put("shopId", shop.getId());
            }
        };
    }

    /**
     * 新增商家（扫码注册）
     *
     * @param param 请求参数 店铺经营类型
     * @return
     * @throws Exception
     * @throws AccountExistedException
     */
    @Transactional
    public Map<String, Object> add(MerchantScanRegister param) throws AccountExistedException, Exception {
        String mobile = param.getMobile();

		/* 密码格式化类（必须为6位密码） */
        DecimalFormat pwdFormat = new DecimalFormat("000000");

		/* 地区信息 */
        Area area = areaService.getArea(param.getAreaIds(), param.getAreaNames(), param.getAreaId());

		/* 新增商家 */
        Merchant merchant = new Merchant();
        BeanUtils.copyProperties(param, merchant); // 属性复制
        merchant.setUsername(mobile); // 以手机号作为登录帐号
        merchant.setPayPwd(Constant.DEFAULT_PWD); // 设置默认支付密码
        merchant.setArea(area);
        merchant = merchantRepo.saveAndFlush(merchant);
        Long merchantId = merchant.getId();

		/* 自动新增店铺 */
        ShopRegister shopRegister = new ShopRegister();
        BeanUtils.copyProperties(param, shopRegister); // 属性复制

		/* 创建店铺帐号 */
        int iPwd = new Random().nextInt(999999); // 随机6位密码
        String password = pwdFormat.format(iPwd);
        shopRegister.setPassword(password);
        Shop shop = shopService.addWithoutMac(shopRegister, merchant, area);

        return new HashMap<String, Object>() {
            private static final long serialVersionUID = 1L;

            {
                put("merchantId", merchantId);
            }

            {
                put("shopId", shop.getId());
            }
        };
    }

    /**
     * 商家登录
     *
     * @param param 登录请求参数
     * @return token
     * @throws Exception
     */
    public Map<String, Object> login(MerchantLogin param) throws Exception {
        String mobile = param.getMobile();

		/* 校验验证码 */
        String key = Constant.CATCHA_LOGIN + mobile; // 商家登录验证码Key=L_手机号
        captchaService.verify(key, param.getCaptcha());

        Merchant merchant = this.findByMobile(mobile);
        if (merchant == null) {
            logger.debug("根据手机号【{}】找不到对应的商家.", mobile);
            throw new MerchantNotFoundException();
        }

        ResponseEntity<Message<?>> response = userFeignClient.getPassword(merchant.getUsername());
        Message<?> message = response.getBody();
        switch (message.getCode()) {
            case 0: // 成功状态
                Map<String, Object> data = (Map<String, Object>) message.getData();
                Token token = loginService.login(merchant.getUsername(), String.valueOf(data.get("password")));
                logger.debug("商家【{}】登录成功，token【{}】", merchant.getId(), token);
                return new HashMap<String, Object>() {
                    private static final long serialVersionUID = 1L;

                    {
                        put("token", token);
                    }

                    {
                        put("merchantId", merchant.getId());
                    }
                };
            case 4: // 帐号不存在
                logger.debug("商家【{}】登录失败，帐号【{}】不存在", merchant.getId(), merchant.getUsername());
                throw new AcountNotFoundException();
            default: // 其它状态码全部判定为异常
                throw new Exception();
        }
    }

    /**
     * 手机号码更改验证
     *
     * @param param 请求参数
     * @throws Exception
     */
    public void changePhoneVerify(MerchantChangePhone param) throws Exception {
        String mobile = param.getMobile();
        /* 校验验证码 */
        String key = Constant.CATCHA_CHANGE_VERIFY + mobile; // 商家登录验证码Key=L_手机号
        captchaService.verify(key, param.getCaptcha());

        Merchant merchant = this.findOne(param.getId());
        if (merchant == null) {
            logger.debug("根据商家id【{}】找不到对应的商家.", param.getId());
            throw new MerchantNotFoundException();
        }
        if (!merchant.getMobile().equals(param.getMobile())) {
            logger.debug("当前商家手机号【{}】，与请求手机号不符【{}】", merchant.getMobile(), param.getMobile());
            throw new IllegalArgumentException();
        }
    }

    /**
     * 手机号码更改确认
     *
     * @param param 参数
     * @throws Exception
     */
    public void changePhoneConfirm(MerchantChangePhone param) throws Exception {
        String mobile = param.getMobile();
		/* 校验验证码 */
        String key = Constant.CATCHA_CHANGE_CONFIRM + mobile; // 商家登录验证码Key=L_手机号
        captchaService.verify(key, param.getCaptcha());
        Merchant merchant = this.findOne(param.getId());
        merchant.setMobile(param.getMobile());
        merchant.setUsername(param.getMobile());
        this.merchantRepo.save(merchant);
    }

    public Merchant update(Long id, MerchantModify param) throws MerchantNotFoundException {
        Merchant merchant = merchantRepo.findOne(id);
        if (merchant == null) {
            throw new MerchantNotFoundException();
        }
        BeanUtils.copyProperties(param, merchant);
        return (Merchant) this.merchantRepo.saveAndFlush(merchant);
    }

    public void delete(Long id) throws MerchantNotFoundException {
        Merchant merchant = merchantRepo.findOne(id);
        if (merchant == null) {
            throw new MerchantNotFoundException();
        }
        merchant.setIsDeleted(true);// 逻辑删除
        merchantRepo.saveAndFlush(merchant);
    }

    /**
     * 商家余额变更
     *
     * @param param 余额变更参数
     * @return Message
     */
    public synchronized Message<?> balanceUpdate(BalanceParam param) {
        Merchant merchant = this.findOne(param.getMerchantId());
        if (merchant == null) {
            logger.info("商家未找到");
            return new Message<>(Result.MERCHANT_NOT_FOUND);
        }
        // if (merchant.getStatus() != merchant_status_ok) {
        // logger.info("商家状态异常");
        // return new Message<>(Result.MERCHANT_STATUS_ERROR);
        // }
        // 商家余额变更
        String msg = "";
        BigDecimal available = merchant.getBalance();
        Byte orderType = null; // 余额变更类型，1 新增，2减少 3.充值返利
        BigDecimal balanceBefore = available.setScale(3, BigDecimal.ROUND_HALF_UP); // 变更前商家余额
        if (param.getOperation() == balance_add) {
            orderType = (byte) 1;
            available = merchant.getBalance().add(param.getMoney());
            msg = "余额增加 " + param.getMoney().doubleValue() + "元";
            logger.debug("商家ID【{}】，余额增加:【{}】", param.getMerchantId(), param.getMoney());
        } else if (param.getOperation() == balance_sub) {
            orderType = (byte) 2;
            available = merchant.getBalance().subtract(param.getMoney());
            msg = "余额扣除 " + param.getMoney().doubleValue() + "元";
            logger.debug("商家ID【{}】，余额扣除:【{}】", param.getMerchantId(), param.getMoney());
        } else if (param.getOperation() == add_profit) {
            orderType = (byte) 3;
            available = merchant.getBalance().add(param.getMoney());
            msg = "充值返利 " + param.getMoney().doubleValue() + " 元";
            logger.debug("商家ID【{}】，充值返利:【{}】", param.getMerchantId(), param.getMoney());
        } else if (param.getOperation() == balance_refund) {
            orderType = (byte) 4;
            available = merchant.getBalance().add(param.getMoney());
            msg = "充值失败退款 " + param.getMoney().doubleValue() + " 元";
            logger.debug("商家ID【{}】，充值失败退款:【{}】", param.getMerchantId(), param.getMoney());
        } else {
            return new Message<>(Result.PARAM_ERROR);
        }
        // 变更后商家余额
        BigDecimal balanceAfter = available.setScale(4, BigDecimal.ROUND_HALF_UP); // 变更后商家余额
        merchant.setBalance(balanceAfter);
        merchantRepo.saveAndFlush(merchant);
        // 余额变更记录
        addBalanceRecord(param, merchant, msg, balanceAfter, orderType, balanceBefore);
        return new Message<>(Result.SUCCESS);
    }

    /**
     * 新增余额变更记录
     *
     * @param param         参数对象
     * @param merchant
     * @param msg           说明
     * @param balanceAfter  变更前余额
     * @param orderType     余额变更类型，1 新增，2减少 3.充值返利 4 充值失败退还
     * @param balanceBefore 变更后余额
     */
    private void addBalanceRecord(BalanceParam param, Merchant merchant, String msg, BigDecimal balanceAfter,
                                  Byte orderType, BigDecimal balanceBefore) {
        BalanceRecord record = new BalanceRecord();
        record.setOrderType(orderType);
        record.setMerchantId(merchant.getId());
        record.setEmployeeNo(param.getEmployeeNo());
        record.setCreateDate(new Date());
        record.setOrderId(param.getOrderId());
        record.setShopId(param.getShopId());
        record.setMessage("1");
        record.setOrderName(param.getOrderName());
        record.setPrice(param.getMoney().setScale(4, BigDecimal.ROUND_HALF_UP));
        record.setBalanceBefore(balanceBefore);
        record.setBalanceAfter(balanceAfter);
        record.setOrderName(msg);
        logger.debug("商家ID【{}】，余额变更记录增加:【{}】", record);
        balanceRepo.save(record);
    }

    /**
     * 保存商家信息
     *
     * @param merchant
     * @return
     */
    public Merchant save(Merchant merchant) {
        return merchantRepo.saveAndFlush(merchant);
    }
    @Autowired
    private ShopRepo shopRepo;
    
    /**
     * 根据名称模糊查询商家
     *
     * @param name
     * @return 返回商家列表项(id, name)
     */
    public Message<?> queryItemList(Long serviceProviderId, String name) {

//        List<Merchant> collect = this.merchantRepo.findAll(new MerchantItemSpec(name, serviceProviderId), new PageRequest(0, 50)).getContent();
    	List<Merchant> collect = this.merchantRepo.findAll(new MerchantItemSpec(name, serviceProviderId));
        List<ItemDto> dtoList = collect.stream()
                .map(merchant -> {
                    ItemDto node = new ItemDto(merchant.getId(), merchant.getName());
//                    node.setParent(new ItemDto(merchant.getServiceProviderId(), null));
                    return node;
                }).sorted(Comparator.comparing(ItemDto::getName))
                .collect(Collectors.toList());
        return new Message<>(Result.SUCCESS, dtoList);
    }

    /**
     * @param merchantId
     * @return
     */
    public Message<?> queryItem(long merchantId) {
        Merchant merchant = this.merchantRepo.findOne(merchantId);
        if (merchant == null) {
            return new Message<>(Result.ERROR, "商家不存在Id：" + merchantId);
        }
        ItemDto itemDto = new ItemDto(merchant.getId(), merchant.getName());
//        itemDto.setParent(new ItemDto(merchant.getServiceProviderId(), null));
        return new Message<>(Result.SUCCESS, itemDto);
    }


    /**
     * 服务商后台新增商家
     */
    @Transactional
    public Merchant addMerchantBySp(SpMerchantAdd param) throws AccountExistedException, Exception {
        String mobile = param.getMobile();
        String roleKey = Constant.ROLE_KEY_SHOP; // 单体店商家角色
        Integer userType = Constant.USER_SHOP; // 用户类型（单体店商家）

//		/* 校验验证码 */
//        String key = Constant.CATCHA_REGISTER + mobile; // 商家注册验证码Key=R_手机号
//        captchaService.verify(key, param.getCaptcha());

		/* 密码格式化类（必须为6位密码） */
        DecimalFormat pwdFormat = new DecimalFormat("000000");

		/* 创建商家帐号 */
        int imPwd = new Random().nextInt(999999); // 随机6位密码
        String merchantPwd = pwdFormat.format(imPwd);
        Acount acount = new Acount(mobile, merchantPwd, mobile, userType, roleKey);
        ResponseEntity<Message<?>> response = userFeignClient.register(acount);
        Message<?> message = response.getBody();
        switch (message.getCode()) {
            case 0: // 成功状态
                Map<String, Object> data = (Map<String, Object>) message.getData();
                logger.debug("商家帐号创建完成, userId【{}】", data.get("userId"));
                break;
            case 3: // 帐号已存在
                throw new AccountExistedException();
            default: // 其它状态码全部判定为异常
                throw new Exception();
        }

		/* 新增商家 */
        Merchant merchant = new Merchant();
        BeanUtils.copyProperties(param, merchant); // 属性复制
        merchant.setUsername(mobile); // 以手机号作为登录帐号
        merchant.setPayPwd(Constant.DEFAULT_PWD); // 设置默认支付密码

		/* 省/市/区 处理 */
        if (param.getDistrict() != null && param.getCity() != null && param.getProvince() != null) {
            Area area = areaService.getArea(param.getProvince(), param.getCity(), param.getDistrict());
            merchant.setArea(area);
        }
        merchant = merchantRepo.saveAndFlush(merchant);
//        Long merchantId = merchant.getId();
//
//		/* 自动新增店铺 */
//        ShopRegister shopRegister = new ShopRegister();
//        BeanUtils.copyProperties(param, shopRegister); // 属性复制
//
//		/* 创建商家帐号 */
//        int iPwd = new Random().nextInt(999999); // 随机6位密码
//        String password = pwdFormat.format(iPwd);
//        shopRegister.setPassword(password);
//
//        Shop shop = shopService.add(shopRegister, merchant);
//        Token token = loginService.login(shop.getUsername(), password);

		/* 构造短信内容 */
        // StringBuffer sms = new StringBuffer();
        // sms.append(mobile).append("/").append(merchantPwd);
        // smsFeignClient.sendSms(mobile, Constant.SMS_TYPE_OK_REGISTER,
        // URLEncoder.encode(sms.toString())); // 下发注册成功短信通知
//        return new HashMap<String, Object>() {
//            private static final long serialVersionUID = 1L;
//
//            {
//                put("token", token);
//            }
//
//            {
//                put("merchantId", merchantId);
//            }
//
//            {
//                put("shopId", shop.getId());
//            }
//        };
        return merchant;
    }

    /**
     * 商家移动支付开关
     *
     * @param merchantId
     * @throws MerchantNotFoundException
     */
    public void verify(Long merchantId, Integer type) throws MerchantNotFoundException {
        Merchant merchant = merchantRepo.findOne(merchantId);
        if (merchant == null) {
            logger.info("商家移动支付开关　商家不存在【{}】", merchantId);
            throw new MerchantNotFoundException("商家移动支付开关　商家id " + merchantId + "商家不存在");
        }
        merchant.setMobilePayment(type);
        merchantRepo.saveAndFlush(merchant);
    }

    /**
     * 商家查询手机支付是否打开
     *
     * @param merchantId
     * @return
     * @throws MerchantNotFoundException
     */
    public Boolean getVerify(Long merchantId) throws MerchantNotFoundException {
        Merchant merchant = merchantRepo.findOne(merchantId);
        if (merchant == null) {
            logger.info("商家查询手机支付是否打开　商家不存在【{}】", merchantId);
            throw new MerchantNotFoundException("商家移动支付开关　商家id " + merchantId + "商家不存在");
        }
        Boolean flag = true;
        Integer mobilePayment = merchant.getMobilePayment();
        if (!(mobilePayment == 2)) {
            flag = false;
        }
        return flag;
    }


    public Message<?> queryMerchantNameByIds(List<Long> ids) {
        List<Merchant> merchantList = this.merchantRepo.findAll(ids);
        Map<Long, String> merchantItem = new HashMap<>();
        merchantList.forEach(merchant -> merchantItem.put(merchant.getId(), merchant.getName()));
        return new Message<>(Result.SUCCESS, merchantItem);
    }


}